package main

import (
	"fmt"
	"time"
)

type Pool struct {
	JobQueue         chan Job //待处理的任务队列
	WorkerCurrentNum int      //当前正在工作的协程数
	MaxWorker        int      //允许最大工作协程数
	Result           chan int //处理完成的任务结果队列
	resultNum        int      //已处理任务数
}

type Job struct {
	ID int
}

type Worker struct {
	Result chan int
}

func (w *Worker) DoJob(job Job) {
	//fmt.Println(job.ID)
	fmt.Println("worker started  job", job.ID)
	w.Result <- job.ID
	fmt.Println("worker finished  job", job.ID)
}

// 往Job任务队列里面放入待处理的job
func (g *Pool) AddJob(job Job) {
	g.JobQueue <- job
}

func (g *Pool) stop() {
	for {
		c1 := <-g.Result
		fmt.Println("接收job", c1, "已处理结果")
		g.WorkerCurrentNum--
		g.resultNum++
	}
}

//  开启协程池
func (g *Pool) Run() {
	go g.stop()

outLoop:
	for {
		if g.WorkerCurrentNum < g.MaxWorker {
			select {
			//   data, ok := <-ch  非阻塞接收数据
			//  data：表示接收到的数据。未接收到数据时，data 为通道类型的零值。
			//   ok：表示是否接收到数据。
			case job, ok := <-g.JobQueue:
				if ok {
					fmt.Println("Waiting for job...")
					worker := &Worker{g.Result}
					go worker.DoJob(job)
					g.WorkerCurrentNum++
				} else {
					break outLoop //JobQueue已经关闭，不需要再创建Worker协程
				}
			}
		}
	}

	//保证JobQueue中18个任务全部被处理时退出run
	for g.resultNum != 18 {
		time.Sleep(time.Second)
	}
}

func main() {
	jobQueue := make(chan Job)
	resultQueue := make(chan int)

	p := &Pool{
		MaxWorker: 5,
		JobQueue:  jobQueue,
		Result:    resultQueue,
		resultNum: 0,
	}

	go func() {
		for i := 0; i < 18; i++ {
			job := Job{i}
			p.AddJob(job)
		}
		close(p.JobQueue)
	}()

	p.Run()

	fmt.Println("Complete main")
}
